package whf.framework.web.struts;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.struts.action.ActionForm;

import whf.framework.entity.AbstractEntity;
import whf.framework.entity.Entity;
import whf.framework.exception.NotFoundException;
import whf.framework.exception.PropertyException;
import whf.framework.i18n.ApplicationResource;
import whf.framework.log.Log;
import whf.framework.log.LogFactory;
import whf.framework.meta.Meta;
import whf.framework.meta.MetaFactory;
import whf.framework.meta.entity.IProperty;
import whf.framework.security.entity.User;
import whf.framework.service.Service;
import whf.framework.util.BeanFactory;
import whf.framework.util.BeanUtils;
import whf.framework.util.StringUtils;
import whf.framework.util.TypeUtils;
import whf.framework.util.Utils;
import whf.framework.validate.ValidateErrors;
import whf.framework.web.Constants;
import whf.framework.web.init.PrepareData;
import whf.framework.web.query.QueryBuilder;

/**
 * @author wanghaifeng
 *
 */
@SuppressWarnings("unchecked")
public class WebDispatchAction extends DispatchAction {
	private static Log log = LogFactory.getLog(WebDispatchAction.class);
	
	/**
	 * 是否已经初始化操作和操作说明
	 * @property boolean:hasRegisteredOperations
	 */
	private boolean hasRegisteredOperations = false;
	
	/**
	 * 类和其拥有的操作
	 * @property Map<Class,Map<String,String>>:operationNames
	 */
	protected static Map<Class, Map<String, String>> operationNames = Utils.newHashMap();
	
	/**
	 * 提供之类一个方便的方法把之类中的操作注册到static的对象中operationNames
	 * @modify wanghaifeng Sep 9, 2006 12:39:07 PM
	 * @param operation 操作名称
	 * @param name		说明
	 */
	protected void registerOperation(String operation, String name){
		Map<String,String> operations = operationNames.get(getClass());
		if(operations == null){
			operations = Utils.newHashMap();
			operationNames.put(getClass(), operations);
		}
		operations.put(operation, name);
	}
	
	/**
	 * 获取当前类的所有操作和说明，如果没有初始化则首先初始化
	 * 初始化既是初始化所有基类中的方法
	 * @modify wanghaifeng Sep 9, 2006 12:37:56 PM
	 * @return
	 */
	public Map<String, String> getOperationNames() {
		if(!hasRegisteredOperations){
			this.registerOperation("create", 	ApplicationResource.get("form.create"));
			this.registerOperation("update", 	ApplicationResource.get("form.update"));
			this.registerOperation("delete", 	ApplicationResource.get("form.delete"));
			this.registerOperation("duplicate",	ApplicationResource.get("form.duplicate"));
			this.registerOperation("search",	ApplicationResource.get("form.search"));
			this.registerOperation("view",		ApplicationResource.get("form.view"));
			this.registerOperation("list",		ApplicationResource.get("form.list"));
			this.registerOperation("saveMultiple",		ApplicationResource.get("form.save_multiple"));
			this.registerOperation("createPropertyElement",		ApplicationResource.get("form.create_property_element"));
			this.registerOperation("deletePropertyElements",	ApplicationResource.get("form.delete_property_element"));
			this.hasRegisteredOperations = true;
		}
		return operationNames.get(getClass());
	}
	
	/**
	 * 对象列表，如果有参数query，将按withoutLazy进行查询数据
	 * @param mapping
	 * @param webEntity
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public WebForward list(AbstractEntity webEntity, WebData data)
			throws Exception {
		String queryString = QueryBuilder.buildQueryString(data.getRequest());
		if(!StringUtils.isEmpty(queryString)) {
			data.setAttribute(Constants.DYNAMIC_QUERY_STRING, queryString);
		}
		data.setAttribute(Constants.STRUTS_LASTEST_WEBMETHOD, "list");
		return data.forward("list");
	}
	
	/**
	 * 查看对象
	 * @param mapping
	 * @param webEntity
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public WebForward view(AbstractEntity webEntity, WebData data)
			throws Exception {
		AbstractEntity entity = (AbstractEntity)getService().findByPrimaryKeyWithoutLazy(webEntity.getId());
		entity.setWebMethod("prepareUpdate");
		data.setAttribute(entity);
		return data.forward("view");
	}
	
	/**
	 * 创建准备
	 * @param mapping
	 * @param webEntity
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public WebForward prepareCreate(AbstractEntity webEntity, WebData data)
			throws Exception {
		webEntity.setWebMethod("create");
		return data.forward("edit");
	}
	
	/**
	 * 创建一个新对象
	 * 系统可以根据tabletag中定义的属性自动获取many-to-one属性对象和collection属性对象
	 * @param mapping
	 * @param webEntity
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public WebForward create(AbstractEntity webEntity, WebData data)
			throws Exception {
		//对于外键属性，从数据库中获取对应对象
		User currentUser = data.getCurrentUser();
		Entity entity = this.initEntity(webEntity, data);
		entity.setActive(true);
		entity.setCreateBy(currentUser);
		ValidateErrors errors = super.validate(data, entity, this.getMeta(), null);
		if(errors != null && !errors.isEmpty()){
			data.setAttribute(Constants.VALIDATE_ERRORS, errors);
			log.debug(errors);
			return prepareCreate((AbstractEntity)entity, data);
		} else {
			data.setCurrentEntity(entity);
			this.handleBeforeCreate(entity);
			getService().create(entity);
			data.setCurrentEntity(entity);
			this.handleAfterCreate(entity);
			return list((AbstractEntity)entity, data);
		}
	}
	
	/**
	 * 提供之类使用，在创建对象之前做一次处理
	 * @modify wanghaifeng Nov 27, 2006 1:02:45 PM
	 * @param entity
	 */
	protected void handleBeforeCreate(Entity entity){
		//default do nothing
	}
	
	/**
	 * 提供子类使用，在创建对象之后做一次处理
	 * @modify wanghaifeng Nov 27, 2006 1:03:31 PM
	 * @param entity
	 */
	protected void handleAfterCreate(Entity entity){
		//default do nothing
	}
	
	/**
	 * 复制对象
	 * @modify wanghaifeng Aug 26, 2006 12:21:57 PM
	 * @param mapping
	 * @param webEntity
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public WebForward duplicate(AbstractEntity webEntity, WebData data)
			throws Exception {
		Meta currentMeta = getMeta();
		Class modelClass = currentMeta.getModelClass();
		long[] ids = data.getIds(modelClass, 0);
		int deepth = data.getIntParameter(Constants.DUPLICATE_DEEPTH, 0);
		if(ids != null )
			for(long id: ids){
				Entity entity = (Entity)getService().findByPrimaryKeyWithoutLazy(id);
				data.setCurrentEntity(entity);
				this.handleBeforeDuplicate(entity);
				getService().duplicate(entity, deepth);
				data.setCurrentEntity(entity);
				this.handleAfterDuplicate(entity);
			}
		return list(webEntity, data);
	}
	
	protected void handleBeforeDuplicate(Entity entity){
		//default do nothing
	}
	
	protected void handleAfterDuplicate(Entity entity){
		//default do nothing
	}
	
	/**
	 * 准备为Collection属性创建一个新属性元素
	 * @param mapping
	 * @param webEntity
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public WebForward prepareCreatePropertyElement(AbstractEntity webEntity, WebData data) throws Exception{
		try{
			Meta currentMeta = getMeta();
			Class modelClass = currentMeta.getModelClass();
			long[] ids = data.getIds(modelClass, 0);
			if(ids == null || ids.length == 0) throw new NotFoundException();
			AbstractEntity entity = (AbstractEntity)getService().findByPrimaryKeyWithoutLazy(ids[0]);
			String propName = data.getParameter(Constants.UPDATING_PROPERTY_NAME);
			PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(modelClass, propName);
			if(descriptor== null || !TypeUtils.isImplementsFrom(descriptor.getPropertyType(), Collection.class)){
				return data.forward(Constants.G_UPDATING_PROPERTY_NOT_FOUND_FORWARD);
			}
			IProperty prop = currentMeta.findProperty(descriptor.getName());
			String dataTypeName = prop.getDataType();
			Meta meta = MetaFactory.findByModelClass(Utils.getClassByClassName(dataTypeName));
			
			data.setAttribute(Constants.STRUTS_META, meta);
			entity.setWebMethod("createPropertyElement");
			data.setAttribute(entity);
		}catch(NotFoundException nfe){
			log.error(this, nfe);
			throw nfe;
		}
		return data.forward("edit_property");
	}

	/**
	 * 为Collection属性创建一个新属性元素
	 * @param mapping
	 * @param webEntity
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public WebForward createPropertyElement(AbstractEntity webEntity, WebData data) throws Exception{
		long id = webEntity.getId();
		Meta currentMeta = getMeta();
		Entity entity = (Entity)getService().findByPrimaryKeyWithoutLazy(id);
		String propName = data.getParameter(Constants.UPDATING_PROPERTY_NAME);
		PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(currentMeta.getModelClass(), propName);
		Collection propValue = (Collection)BeanUtils.getProperty(entity, propName);
		
		IProperty prop = currentMeta.findProperty(descriptor.getName());
		String dataTypeName = prop.getDataType();
		Meta propMeta = MetaFactory.findByModelClass(Utils.getClassByClassName(dataTypeName));
		Entity propElement = (Entity)propMeta.getModelClass().newInstance();
		//assign values
		PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(propMeta.getModelClass());
		for(PropertyDescriptor desc: descriptors){
			String value = data.getParameter(propMeta.getModelClass(), desc.getName());
			propElement.setProperty(desc.getName(), desc.getPropertyType(), value);
		}
		//
		BeanFactory.getService(propMeta).create(propElement);
		propValue.add(propElement);
		getService().update(entity);

		((AbstractEntity)entity).setWebMethod("update");
		data.setAttribute(entity);
		return data.forward("edit");
	}
	
	/**
	 * 准备修改
	 * @modify wanghaifeng Aug 24, 2006 11:12:38 PM
	 * @param mapping
	 * @param webEntity
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public WebForward prepareUpdate(AbstractEntity webEntity, WebData data)
			throws Exception {
		//对于外键对象，获取对象列表
		try{
			long[] ids = data.getIds(getMeta().getModelClass(), 0);
			if(ids == null || ids.length == 0) throw new NotFoundException();
			AbstractEntity entity = (AbstractEntity)getService().findByPrimaryKeyWithoutLazy(ids[0]);
			entity.setWebMethod("update");
			data.setAttribute(entity);
		}catch(NotFoundException nfe){
			log.error(this, nfe);
			throw nfe;
		}
		return data.forward("edit");
	}
	
	public WebForward update(AbstractEntity webEntity, WebData data)
			throws Exception {
		//对于外键属性，从数据库中获取对应对象
		webEntity.setUpdateBy(data.getCurrentUser());
		Meta meta = getMeta();
		long[] ids = data.getIds(meta.getModelClass(), 0);
		long idKey = 0;
		if(ids != null && ids.length > 0){
			idKey = ids[0];
		}
		Entity entity = this.findAndAssignFormValues(webEntity, data, idKey);
		this.initAllSlaveDatas(entity, data);
		ValidateErrors errors = super.validate(data, entity, meta, null);
		if(errors != null && !errors.isEmpty()){
			data.setAttribute(Constants.VALIDATE_ERRORS, errors);
			return prepareUpdate((AbstractEntity)entity, data);
		} else {
			data.setCurrentEntity(entity);
			this.handleBeforeUpdate(entity);
			getService().update(entity);
			data.setCurrentEntity(entity);
			this.handleAfterUpdate(entity);
			return list((AbstractEntity)entity, data);
		}
	}
	
	/**
	 * 修改之前做处理
	 * @modify wanghaifeng Nov 27, 2006 1:05:13 PM
	 * @param entity
	 */
	protected void handleBeforeUpdate(Entity entity){
		//do nothing
	}
	
	/**
	 * 修改之后所作的处理
	 * @modify wanghaifeng Nov 27, 2006 1:05:42 PM
	 * @param entity
	 */
	protected void handleAfterUpdate(Entity entity){
		//do nothing
	}

	/**
	 * 保存多个对象,当TableTag是Table时并且Editable＝true
	 * @modify wanghaifeng Aug 24, 2006 11:35:50 PM
	 * @param mapping
	 * @param webEntity
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public WebForward saveMultiple(AbstractEntity webEntity, WebData data)
			throws Exception {
		Meta meta = getMeta();
		String namePrefix = data.getNamePrefix(meta.getModelClass());
		boolean pkSuffix = data.isPkSuffix(meta.getModelClass()); 
		Collection<Entity> collection = this.getUpdatedDatas(null, data, meta.getModelClass(), namePrefix, pkSuffix);
		Service service = getService();
		for(Entity entity: collection){
			if(entity.getId() == 0){
				service.create(entity);
			} else {
				service.update(entity);
			}
		}
		return list(webEntity, data);
	}
	
	/**
	 * 删除对象
	 * @modify wanghaifeng Aug 24, 2006 11:36:43 PM
	 * @param mapping
	 * @param webEntity
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public WebForward delete(AbstractEntity webEntity, WebData data)
			throws Exception {
		long[] ids = data.getIds(getMeta().getModelClass(), 0);
		this.handleBeforeDelete(getMeta().getModelClass(), ids);
		getService().removeByPrimaryKey(ids);
		return list(webEntity, data);
	}
	
	protected void handleBeforeDelete(Class modelClass, long[] ids){
		//default do nothing
	}
	
	protected void handleAfterDelete(Class modelClass, long[] ids){
		//default do nothing
	}
	
	/**
	 * delete elements in the collection of an object
	 */
	public WebForward deletePropertyElements(AbstractEntity webEntity, WebData data)
			throws Exception {
		Meta meta = getMeta();
		Map<String, Class> properties = this.getCollectionPropertiesAndElementClass(data, meta.getModelClass());
		for(String propertyName: properties.keySet()){
			Class propertyType = properties.get(propertyName);
			long[] ids = data.getIds(propertyType, 0); 
			Service service = BeanFactory.getService(MetaFactory.findByModelClass(propertyType));
			service.removeByPrimaryKey(ids);
		}
		long[] ids = data.getIds(meta.getModelClass(), 0);
		Entity entity = (Entity)getService().findByPrimaryKeyWithoutLazy(ids[0]);
		((AbstractEntity)entity).setWebMethod("update");
		data.setAttribute(entity);
		return data.forward("edit");
	}
	
	@Override
	public WebForward unspecified(AbstractEntity form, WebData data) throws Exception {
		return this.list(form, data);
	}
	
	/**
	 * 准备搜索
	 * @modify wanghaifeng Aug 24, 2006 11:37:57 PM
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	protected WebForward prepareSearch(AbstractEntity form, WebData data) throws Exception{
		form.setWebMethod("search");
		return data.forward("search");
	}

	//初始化数据，供子类覆盖
	/**
	 * @param request
	 * @return Key：propertyName,  Value: conditionString
	 */
	protected Map<String, String> getPrepareCreateParameters(){
		return super.defaultQueryParameters;
	}
	
	/**
	 * 获取需要求修改的参数
	 * @modify wanghaifeng Aug 24, 2006 11:20:07 PM
	 * @param request
	 * @return
	 */
	protected Map<String, String> getPrepareUpdateParameters(){
		return super.defaultQueryParameters;
	}
	
	/**
	 * 准备数据
	 * @deprecated 响应的已由WithoutLazy等方法实现这个已经不在需要
	 * @modify wanghaifeng Aug 24, 2006 11:27:03 PM
	 * @param request
	 * @param parameters
	 */
	protected void prepareData(WebData data, Map<String, String> parameters){
		PrepareData prepare = new PrepareData(super.getMeta(), parameters);
		Map<String, List> map = prepare.getData();
		for(String key: map.keySet()){
			data.setAttribute(key, map.get(key));
		}
	}
	
	/**
	 * 初始化需要创建的数据
	 * @param webEntity 由struts创建并初始化的对象
	 * @param request
	 * @return
	 */
	protected Entity initEntity(Entity webEntity, WebData data) {
		try{
			return this.findAndAssignFormValues(webEntity, data, 0);
		}catch(Exception e){
			log.error(this, e);
			return webEntity;
		}
	}
	
	/**
	 * 更新对象前，先从数据库中取出原始对象，然后把客户端提交过的数据复制给原始对象，最后update原始对象，达到修改目的
	 * @param webEntity
	 * @param request
	 * @return
	 * @throws Exception
	 */
	protected Entity findAndAssignFormValues(Entity webEntity, WebData data, long formId) throws Exception{
		Meta meta = getMeta();
		Class modelClass = meta.getModelClass();
		String namePrefix = data.getNamePrefix(modelClass);
		boolean isPkSuffix = data.isPkSuffix(modelClass);
		PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(modelClass);
		Entity entity = null;
		if(formId > 0){//如果修改则首先获取原对象，这样可以保证不需要修改的属性取的是原值，对于collection属性则可以判断增加，删除情况
			entity = (Entity)getService().findByPrimaryKeyWithoutLazy(formId); //for update data
		} else if(StringUtils.isEmpty(namePrefix) && !isPkSuffix){ //与struts对象一样，因此不需要额外处理
			entity = webEntity;
		} else {//创建一个新对象
			entity = (Entity)modelClass.newInstance(); // for create a new object
		}
		for(PropertyDescriptor descriptor: descriptors){
			String propertyName = descriptor.getName();
			String paramName = namePrefix+propertyName;
			if(isPkSuffix) paramName = paramName + webEntity.getId();  //request中参数名称
			String boParamName = paramName+Constants.BOID_SUFFIX;     //如果是many-to-one属性或者collection属性，其request中的参数名称
			Class propertyType = descriptor.getPropertyType();
			if(!TypeUtils.isPrimitiveType(propertyType) && !TypeUtils.isImplementsFrom(propertyType, Entity.class)){
				Field field = BeanUtils.getField(modelClass, propertyName);
				if(field != null){
					propertyType = field.getType();
				}
			}
			if(BeanUtils.hasProperty(ActionForm.class, propertyName) || 
					(!data.containsParameter(paramName) && !data.containsParameter(boParamName))){ //如果request中的参数不包括其名称，属性不需要修改
				continue;
			}
			//
			if(TypeUtils.isImplementsFrom(propertyType, Collection.class)){ //对于集合属性进行初始化
				this.initCollectionProperties(entity, data, propertyName);
			} else if(TypeUtils.isImplementsFrom(propertyType, Entity.class)){    //如果时many-to-one属性则在这里初始化
				this.initManyToOneDatas(entity, data, propertyName, propertyType);
			} else if(propertyType.isEnum()){	//对于枚举类型处理
				String value = data.getParameter(meta.getModelClass(), propertyName);
				try{
					entity.setProperty(propertyName, Enum.valueOf(propertyType, value));
				}catch(Exception e){
					log.debug("Enum value error!" + e.toString());
				}
			} else if(TypeUtils.isPrimitiveType(propertyType)){                     //其它属性类型，可以是int, double, date等
				String value = data.getParameter(meta.getModelClass(), propertyName);
				try{
					entity.setProperty(propertyName, descriptor.getPropertyType(), value);
				}catch(PropertyException ignore){
					log.debug(this, ignore);
				}
			}
		}
		return entity;
	}
	
	/**
	 * 初始化many-to-one关系的对象
	 * @param thisBo
	 * @param request
	 * @return
	 */
	protected void initManyToOneDatas(Entity thisBo, WebData data, String propertyName, Class propertyType){
		try{
			Object propertyValue = data.getData(propertyName);	//如果data中已经存在则优先存取
			if(propertyValue != null && propertyValue.getClass() == propertyType){
				thisBo.setProperty(propertyName, propertyValue);
				return;
			}
			Entity entity = data.getBoParameterWithoutLazy(propertyType, propertyName, 0, thisBo.getId());
			if(entity != null){
				thisBo.setProperty(propertyName, entity);
			}
		}catch(PropertyException e){
			log.info(this, e);
		}
	}
	
	/**
	 * 初始化集合属性
	 * @param entity 数据库中的原业务对象
	 * @param propertyName 属性名称
	 * @param request
	 */
	protected void initCollectionProperties(Entity entity, WebData data, String propertyName){
		long[] ids = data.getCollectionPropertyIds(entity, propertyName, 0);
		try{
			IProperty prop = getMeta().findProperty(propertyName);
			if(prop == null) return;
			Collection values = (Collection)BeanUtils.getProperty(entity, propertyName);
			String propertyTypeName = prop.getDataType();
			Class propertyType = Class.forName(propertyTypeName);
			Service service = BeanFactory.getService(MetaFactory.findByModelClass(propertyType));
			for(Iterator it = values.iterator(); it.hasNext(); ){ //删除集合属性中没有在request中的元素
				Entity oldBo = (Entity)it.next();
				boolean found = false;
				for(long id: ids){
					if(oldBo.getId() == id){
						found = true;
						break;
					}
				}
				if(!found){
					it.remove();
				}
			}
			for(long id : ids){ // 添加不在属性集合中的元素但是在request中的元素；
				if( id <= 0) continue;
				boolean found = false;
				for(Iterator it = values.iterator(); it.hasNext(); ){
					Entity oldBo = (Entity)it.next();
					if(oldBo.getId() == id){
						found = true;
						break;
					}
				}
				if(!found){
					values.add(service.findByPrimaryKeyWithoutLazy(id));
				}
			}
		}catch(Exception e){
			log.error(this, e);
		}
	}
	/**
	 * Master-Slave
	 * @param request
	 * @return
	 */
	protected Map<String, Class> getCollectionPropertiesAndElementClass(WebData data, Class parentObjectClass){
		Map<String, Class> result = new HashMap<String, Class>();
		List<String> paramNames = data.getParameterNames();
		for(String paramName: paramNames){
			if(StringUtils.endsWith(paramName, Constants.DATASOURCE_NAME)){
				String propertyName = data.getParameter(paramName);
				if(StringUtils.isEmpty(propertyName)) continue;
				String className = paramName.substring(0, paramName.indexOf(Constants.DATASOURCE_NAME));  //search the element class of the property
				if(propertyName.indexOf(".")!= -1)
					propertyName = propertyName.substring(propertyName.indexOf(".")+1); //decide the propertyName in webEntity
				if(!BeanUtils.hasProperty(parentObjectClass, propertyName)) continue;
				try{
					Class propClass = Class.forName(className);
					result.put(propertyName, propClass);
				}catch(ClassNotFoundException e){
					continue;
				}
			}
		}
		return result;
	}
	
	/**
	 * according the datasourceName property, search all properties and init these their datas
	 * @param webEntity parent object is
	 * @param request
	 * @throws Exception
	 */
	protected void initAllSlaveDatas(Entity webEntity, WebData data) throws Exception{
		Map<String, Class> properties = this.getCollectionPropertiesAndElementClass(data, getMeta().getModelClass());
		for(String propertyName: properties.keySet()){
			this.initSlaveDatas(webEntity, data, propertyName, properties.get(propertyName));
		}
	}
	
	/**
	 * 同时更新主从表时，获取从表数据
	 * initialize the slave datas(a collection property, such as set, list and so on)
	 * @param webEntity
	 * @param propertyName
	 * @param propClass
	 * @param request
	 * @throws Exception
	 */
	protected void initSlaveDatas(Entity webEntity, WebData data, String propertyName, Class propClass) throws Exception{
		if(StringUtils.isEmpty(propertyName)) return; 
		if(StringUtils.startsWith(propertyName, ".")){ //check propertyName
			propertyName = propertyName.substring(1);
		}
		if(!BeanUtils.hasProperty(getMeta().getModelClass(), propertyName)){ //check property is exists
			return;
		}
		//Property Name OK
		
		//Get Property Class, if null create it
		if(propClass == null ){
			String propClassName = "";
			String[] propClassNames = data.getParameterValues(Constants.BO_CLASS_NAME);
			for(int i=0;propClassNames!=null && i< propClassNames.length; i++){
				String dsn = propClassNames[i]+Constants.DATASOURCE_NAME;
				String prop = data.getParameter(dsn);
				if(prop == null) continue;
				if(prop.endsWith("."+propertyName)){
					propClassName = propClassNames[i];
					break;
				}
			}
			if(StringUtils.isEmpty(propClassName)){
				return;
			}
			try{
				propClass = Class.forName(propClassName);
			}catch(ClassNotFoundException e){
				log.info("Can not found Class:"+propClassName);
				return;
			}
		}
		//Property Type Class OK
		//
		String namePrefix = data.getNamePrefix(propClass);
		boolean pkSuffix = data.isPkSuffix(propClass);
		//
		 // get the collection property values, so we can update one by one
		Collection<Entity> collection = BeanUtils.convert2BoList((Collection)BeanUtils.getProperty(webEntity, propertyName));
		//	get the updated values
		collection = getUpdatedDatas(collection, data, propClass, namePrefix, pkSuffix); 
	}

	/**
	 * @modify wanghaifeng Aug 9, 2006 1:38:04 PM
	 * 多行更新时，获取多行更新数据
	 * @param collection
	 * @param request
	 * @param boClass
	 * @param namePrefix
	 * @param pkSuffix
	 * @return
	 * @throws Exception
	 */
	protected Collection<Entity> getUpdatedDatas(Collection<Entity> collection, WebData data, Class boClass, String namePrefix, boolean pkSuffix) throws Exception{
		if(collection == null){
			// if collection is null ,we need create a new one
			collection = new ArrayList<Entity>();
		}
		List<String> paramNames = data.getParameterNames();
		PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(boClass);
		//get all elements' id
		long[] ids = data.getLongParameters(namePrefix+Constants.ID, 0); 
		if(ids == null) return collection;
		for(long id: ids){
			Entity newEntity = null;
			boolean isCreate = false;
			for(Entity entity : collection){ //decide the id exists
				if(entity.getId() == id){
					newEntity = entity;
					break;
				}
			}
			if (newEntity == null){
				newEntity = (Entity)boClass.newInstance();
				isCreate = true;
			}
			for(PropertyDescriptor descriptor: descriptors){ //loop for all properties
				String paramName = namePrefix+descriptor.getName();
				Class propertyType = descriptor.getPropertyType();
				Object propertyValue = null;
				if(pkSuffix){
					paramName = paramName + id;
				}
				if(!paramNames.contains(paramName)){ //if the param not in request params, continue
					continue;
				}else if(BeanUtils.hasProperty(ActionForm.class, descriptor.getName())){  //skip actionForm's properties
					continue;
				}else if(TypeUtils.isExtendsFrom(propertyType, Entity.class)){ // many-to-one property
					long pId = data.getLongParameter(paramName+"Id", -1);
					if(pId == -1){
						continue;
					}else{
						try{
							propertyValue = BeanFactory.getService(MetaFactory.findByModelClass(propertyType)).findByPrimaryKeyWithoutLazy(pId);
						}catch(Exception e){
							log.info(this, e);
						}
					}
				} else if(propertyType == int.class){
					int iValue = data.getIntParameter(paramName, -1);
					if(iValue != -1){
						propertyValue = new Integer(iValue);
					}
				} else if(propertyType == long.class){
					long iValue = data.getLongParameter(paramName, -1);
					if(iValue != -1){
						propertyValue = new Long(iValue);
					}
				} else if(propertyType == boolean.class){
					boolean iValue = data.getBooleanParameter(paramName);
					propertyValue = new Boolean(iValue);
				} else if(propertyType == String.class){
					propertyValue = data.getParameter(paramName);
				} else if(propertyType == java.util.Date.class){
					propertyValue = StringUtils.parseDate(data.getParameter(paramName));
				} else if(propertyType == java.sql.Date.class){
					java.util.Date d = StringUtils.parseDate(data.getParameter(paramName));
					if(d != null){
						propertyValue = new java.sql.Date(d.getTime());
					}
				}
				if(propertyValue != null){
					BeanUtils.setProperty(newEntity, descriptor.getName(), propertyValue);
				}
			}
			if(isCreate){
				collection.add(newEntity);
			}
		}
		return collection;
	}
	
	public static void main(String[] args) throws Exception{
		System.out.println(BeanUtils.hasProperty(ActionForm.class, "private"));
	}
}
